'''
Created on 09-Jul-2010

@author: asa
'''

from twisted.web.resource import Resource
from twisted.web.server import NOT_DONE_YET
from twisted.web.server import Site
from UpdateEntangledNode import UpdateEntangledNode
from sg.edu.ntu.metaweb.storage.WebPage import WebPage
from sg.edu.ntu.metaweb.storage.Comment import Comment
import hashlib
  
class DoCommand(Resource):
    """
    Handler for HTTP requests.
    """
    isLeaf = True
         
    def render(self, request):
        """
        This method will be called for every incoming request.
        
        If the response string can be returned right away
        return the response string.
        If not, return NOT_DONE_YET.
        """
        if len(request.args['command']) == 0:
            return
        else :
            command = request.args['command'][0]
            if command == 'new_comment':
                action = AddComments(request)
            elif command == 'get_comments':
                action = GetComments(request)
                action.executeAction()
                return NOT_DONE_YET
            else:
                action = Action(request)
                
            #make this return from deffered object callback
            return action.executeAction()
    
class Action:
    def __init__(self, request):
        self.request = request
    
    def executeAction(self):
        return "<html><body>" + str(self.request.args) + "</body></html>"
    
class AddComments(Action):
    def __init__(self, request):
        Action.__init__(self, request)
        
    def executeAction(self):
        print "add comments..."
        key = "webpage_" + self.request.args['url'][0]
        value = node.searchForKeywords(key)
        if len(value.result) == 0:
            insertAction = InsertWebPage(self.request)
            insertAction.executeAction()
        parent_id = -1
        if self.request.args.has_key('parent_id') and \
                self.request.args['parent_id'][0] != '-1':
            parent_id = int(self.request.args['parent_id'][0][8:])
        newcomment = Comment(self.request.args['username'][0],
                             self.request.args['content'][0], 
                             parent_id)
        node.updateByName(key, self, newcomment)
        temp = "<xmlresponse>\n<returncode>1</returncode>\n</xmlresponse>"
        return temp
    
    def applyUpdate(self, webpage, newcomment):
        """ 
        This method will be called by the update rpc.
        All Action that updates an object should have applyUpdate(self, original, diff) method.
        """
        webpage.addComment(newcomment)
        return webpage

class GetComments(Action):
    def __init__(self, request):
        Action.__init__(self, request)
        
    def executeAction(self):
        print "get comments..."
        key = "webpage_" + self.request.args['url'][0]
        h = hashlib.sha1()
        h.update(key)
        key = h.digest()
        request = self.request
        def resultReceivedCallback(result):
            print "in get comments result"
            request.write(self.resultReceived(key, result))
            request.finish()
        value = node.iterativeFindValue(key)
        value.addCallback(resultReceivedCallback)
        
    def resultReceived(self, key, result):
        temp = "<xmlresponse>\n"
        if type(result) is dict:
            temp += "<resultno>" + str(result[key].getCommentsNumber()) + "</resultno>\n" \
                 + "<comments>\n"
            for c in result[key].comments:
                temp += str(result[key].comments[c]) + "\n"
            temp += "</comments>\n"
        else:
            temp += "<resultno>0</resultno>\n"
        temp += "</xmlresponse>"
        print temp
        return temp
        
class InsertWebPage(Action):
    def __init__(self, request):
        Action.__init__(self, request)
    
    def executeAction(self):
        print "insert web page ..."
        url = self.request.args['url'][0]
        webpage = WebPage(url)
        node.publishData(webpage.key, webpage)
    
if __name__ == "__main__":
    from twisted.internet import reactor
    from entangled.kademlia.datastore import SQLiteDataStore
    import sys, os
    
    if len(sys.argv) < 2:
        print 'Usage:\n%s UDP_PORT  [KNOWN_NODE_IP  KNOWN_NODE_PORT]' % sys.argv[0]
        print 'or:\n%s UDP_PORT  [FILE_WITH_KNOWN_NODES]' % sys.argv[0]
        print '\nIf a file is specified, it should containing one IP address and UDP port\nper line, separated by a space.'
        sys.exit(1)
    try:
        int(sys.argv[1])
    except ValueError:
        print '\nUDP_PORT must be an integer value.\n'
        print 'Usage:\n%s UDP_PORT  [KNOWN_NODE_IP  KNOWN_NODE_PORT]' % sys.argv[0]
        print 'or:\n%s UDP_PORT  [FILE_WITH_KNOWN_NODES]' % sys.argv[0]
        print '\nIf a file is specified, it should contain one IP address and UDP port\nper line, separated by a space.'
        sys.exit(1)

    if len(sys.argv) == 4:
        knownNodes = [(sys.argv[2], int(sys.argv[3]))]
    elif len(sys.argv) == 3:
        knownNodes = []
        f = open(sys.argv[2], 'r')
        lines = f.readlines()
        f.close()
        for line in lines:
            ipAddress, udpPort = line.split()
            knownNodes.append((ipAddress, int(udpPort)))
    else:
        knownNodes = None

    if os.path.isfile('/tmp/dbFile%s.db' % sys.argv[1]):
        os.remove('/tmp/dbFile%s.db' % sys.argv[1])
    dataStore = SQLiteDataStore(dbFile = '/tmp/dbFile%s.db' % sys.argv[1])
    global node
    node = UpdateEntangledNode( udpPort=int(sys.argv[1]), dataStore=dataStore )
    #node = EntangledNode( udpPort=int(sys.argv[1]) )
    node.joinNetwork(knownNodes)

    # HTTP SERVER
    resource = DoCommand()
    factory = Site(resource)
    
    reactor.listenTCP(8080, factory)
    reactor.run()
